package cn.yx.common.core.util.bean;

import cn.hutool.core.collection.CollectionUtil;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.groups.Default;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * <p>使用javax.validation提供的API进行对象验证，需要相应的Provider，如hibernate-validator</p>
 *
 * @author Wgssmart
 */
public final class ValidateUtil {

    private static Validator validator;

    private ValidateUtil() {
    }

    // 静态代码块初始化Validator，并且使用单例模式
    static {
        synchronized (Object.class) {
            if (Objects.isNull(validator)) {
                synchronized (Object.class) {
                    try (ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory()) {
                        validator = validatorFactory.getValidator();
                    }
                }
            }
        }
    }

    /**
     * 验证对象的所有属性是否符合指定的数据要求
     *
     * @param t   需要验证的对象
     * @param <T> 验证对象为泛型
     * @return 如果验证有错，则返回验证错误信息，否则返回null
     */
    public static <T> String validate(T t) {
        return getValidateMessage(validator.validate(t, Default.class));
    }

    /**
     * 验证对象指定的单个属性是否符合指定的数据要求
     *
     * @param t        需要验证的对象
     * @param property 对象中的属性名
     * @param <T>      验证对象为泛型
     * @return 如果验证有错，则返回验证错误信息，否则返回null
     */
    public static <T> String validate(T t, String property) {
        return getValidateMessage(validator.validateProperty(t, property, Default.class));
    }

    /**
     * 验证对象指定的多个属性是否符合指定的数据要求
     *
     * @param t          需要验证的对象
     * @param properties 对象中的多个属性名
     * @param <T>        验证对象为泛型
     * @return 如果验证有错，则返回验证错误信息，否则返回null
     */
    public static <T> String validate(T t, String[] properties) {
        Set<ConstraintViolation<T>> allConstraintViolation = new HashSet<>();
        for (String property : properties) {
            Set<ConstraintViolation<T>> constraintViolationSet = validator.validateProperty(t, property);
            allConstraintViolation.addAll(constraintViolationSet);
        }
        return getValidateMessage(allConstraintViolation);
    }

    /**
     * 从ConstraintViolation集合中获取数据验证的错误信息
     *
     * @param constraintViolationSet ConstraintViolation集合
     * @param <T>                    验证对象
     * @return 如果有错误消息，则组装成String字符中返回，否则返回null
     */
    private static <T> String getValidateMessage(Set<ConstraintViolation<T>> constraintViolationSet) {
        if (CollectionUtil.isEmpty(constraintViolationSet)) {
            return null;
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (ConstraintViolation<T> cv : constraintViolationSet) {
            stringBuilder.append(cv.getMessage()).append(";");
        }
        return stringBuilder.toString();
    }

}
